package main

import (
	"bytes"
	"fmt"
	"html/template"
	"log"
	"reflect"
	"strings"
)

type structInfo struct {
	T     *schema
	Name  string   //结构体名
	Num   int      //结构体字段的个数
	Field []filed  //结构体字段
	Tag   []string //结构体字段的Tag
	Path  string   //生成的结构体存放路径
	Pkg   string   //生成的结构体存放在哪个包下
}

func (l structInfo) convert(obj interface{}) structInfo {
	t := reflect.TypeOf(obj)
	k := t.Kind()
	if k == reflect.Ptr {
		t = t.Elem()
	}
	l.Num = t.NumField()
	l.Name = t.Name()
	for i := 0; i < l.Num; i++ {
		field := t.Field(i)
		l.Field = append(l.Field, filed{
			Name: field.Name,
			Type: field.Type,
		})
	}
	return l
}

type filed struct {
	Name string       //字段名
	Type reflect.Type //字段类型
	Tag  string       //字段Tag
}

func snake(s string) string {
	res := make([]byte, 0, len(s)*2)
	j := false
	num := len(s)
	for i := 0; i < num; i++ {
		d := s[i]
		if i > 0 && d >= 'A' && d <= 'Z' && j {
			res = append(res, '_')
		}
		if d != '_' {
			j = true
		}
		res = append(res, d)
	}
	return strings.ToLower(string(res[:]))
}

func Convert(pkg string, obj interface{}) (err error) {
	l := structInfo{}
	str := l.convert(obj)
	if str.Tag == nil {
		str.Tag = []string{"json", "form", "db", "binding"}
	}
	s := fmt.Sprintf(`
package %s
import (
	"time"
)
`, pkg) //req.EntityPkg
	s2 := fmt.Sprintf(`
package %s
`, pkg)
	l.Name = str.Name
	var fieldType bool
	for _, val := range str.Field {
		if val.Type.String() == "time.Time" {
			fieldType = true
		}
		l.Field = append(l.Field, filed{
			Name: val.Name,
			Type: val.Type,
			Tag:  l.T.formatField(snake(val.Name), str.Tag),
		})
	}
	pkg = l.T.createDir("./"+pkg) + "/" + l.Name + ".go"

	check := "time"
	if l.T.checkFileContainsChar(pkg, check) == false && fieldType {
		l.T.writeFile(pkg, s)
	} else {
		l.T.writeFile(pkg, s2)
	}
	if l.T.checkFileContainsChar(pkg, "type "+l.Name+" struct") == true {
		log.Println(l.Name + "已经存在。请删除该结构体并重新生成")
		return
	}

	tplByte, err := f.ReadFile(tplObj)
	if err != nil {
		return
	}

	tpl, err := template.New(pkg).Parse(string(tplByte))
	if err != nil {
		return
	}

	content := bytes.NewBuffer([]byte{})
	tpl.Execute(content, l)

	con := strings.Replace(content.String(), "&#34;", `"`, -1)
	err = l.T.writeFileAppend(pkg, con)
	if err != nil {
		return
	}
	return
}
